/**
 * Created by rockyl on 2020/12/8.
 */
import {file2DataUrl} from "./utils";

interface PickFileOptions {
    accept?: string
    multiple?: boolean
    inputElement?: HTMLInputElement
}

interface PickImageOptions extends PickFileOptions {

}

interface PickTextOptions extends PickFileOptions {

}

interface PickJsonOptions extends PickFileOptions {

}

let _inputEl: HTMLInputElement

function getSharedInputEl() {
    let inputEl = _inputEl
    if (!inputEl) {
        inputEl = _inputEl = document.createElement('input')
        inputEl.type = 'file'
        inputEl.style.visibility = 'hidden'
        inputEl.style.position = 'absolute'
        inputEl.style.left = '-9999px'
        document.body.appendChild(inputEl)
    }
    return inputEl
}

/**
 * pickFile
 * @desc pick file(s)
 * @param opts - options
 * @example pick a image file
 * const files = await pickFile('image/*')
 * console.log('picked file：', files[0].name)
 */
export function pickFile(opts: PickFileOptions = {}): Promise<File[]> {
    const {accept, multiple = false, inputElement} = opts

    return new Promise((resolve, reject) => {
        let picked = false
        let inputEl: HTMLInputElement
        if (inputElement) {
            inputEl = inputElement
        } else {
            inputEl = getSharedInputEl()
        }
        inputEl.accept = accept
        inputEl.multiple = multiple

        inputEl.addEventListener('change', onChange, {once: true})
        window.addEventListener('focus', onWindowFocus, {once: true})
        inputEl.click()

        function onChange(e) {
            let files = []
            for (let i = 0, li = inputEl.files.length; i < li; i++) {
                const file = inputEl.files[i]
                files.push(file)
            }
            inputEl.files = null
            inputEl.value = ''
            clear()
            picked = true
            resolve(files)
        }

        function onWindowFocus() {
            setTimeout(() => {
                //console.log('focus', input.files)
                if (!picked && inputEl.files.length === 0) {
                    clear()
                    reject('cancel')
                }
            }, 500)
        }

        function clear() {
            inputEl.removeEventListener('change', onChange)
            window.removeEventListener('focus', onWindowFocus)
        }
    })
}

/**
 * pickImage
 * @description pick a image
 * @param opts - options
 * @example pick a image as dataUrl
 * const dataUrl = await pickImage()
 * console.log('image dataUrl:', dataUrl);  //…
 */
export async function pickImage(opts: PickImageOptions = {}): Promise<string> {
    const files = await pickFile(Object.assign({accept: 'image/*'}, opts))
    if (files.length > 0) {
        return file2DataUrl(files[0])
    }
}

/**
 * pickText
 * @description pick a text
 * @param opts - options
 * @example pick a text
 * const text = await pickText()
 * console.log('text:', text);
 */
export async function pickText(opts: PickTextOptions): Promise<string> {
    const files = await pickFile(Object.assign({accept: 'text/*'}, opts))
    if (files.length > 0) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.onload = function () {
                resolve(reader.result as string)
            }
            reader.onerror = function (e) {
                reject(e)
            }
            reader.readAsText(files[0])
        })
    }
}

/**
 * pickJson
 * @description pick a json object
 * @param opts - options
 * @example pick a json object
 * const json = await pickJson()
 * console.log('json object:', json);
 */
export async function pickJson(opts: PickJsonOptions): Promise<any> {
    const text = await pickText(Object.assign({accept: 'application/json'}, opts))
    return JSON.parse(text)
}
